#include "http_connection.h"

const char *HttpConnection::m_src_dir;
std::atomic<int> HttpConnection::m_clients_cnt;
bool HttpConnection::is_ET_mode;

HttpConnection::HttpConnection(uint64_t read_buf_size, uint64_t write_buf_size) {
    m_is_close = true;
    m_bytes_to_send = 0;
    m_bytes_have_sent = 0;
    m_Request.init_read_buffer(read_buf_size);
    m_Response.init_write_buffer(write_buf_size);
}

HttpConnection::~HttpConnection() {
    m_Response.unmap_file();
    close_conn();
}

void HttpConnection::init(int sockfd, const sockaddr_in &addr_in) {
    m_client_fd = sockfd;
    m_client_addr = addr_in;
    m_clients_cnt++;
    m_is_close = false;
    reset();
}

void HttpConnection::reset() {
    m_bytes_to_send = 0;
    m_bytes_have_sent = 0;
    m_Request.reset();
    m_Response.reset();
}

void HttpConnection::close_conn() {
    m_Response.unmap_file();
    if (!m_is_close) {
        m_is_close = true;
        m_clients_cnt--;
        close(m_client_fd);
    }
}

bool HttpConnection::read_data() {
//    int test_fd = open("./read_buffer", O_RDWR | O_APPEND);

    // 读出错时返回false，读成功返回true
    if (m_Request.m_read_idx >= m_Request.m_read_buf_size) {
        return false;
    }

    long read_bytes;
    do {
        read_bytes = recv(m_client_fd, m_Request.m_read_buffer + m_Request.m_read_idx,
                          m_Request.m_read_buf_size - m_Request.m_read_idx, 0);

//        if (read_bytes){
//            write(test_fd, m_Request.m_read_buffer + m_Request.m_read_idx, read_bytes);
//        }

        if (read_bytes <= 0) {
            if (is_ET_mode && errno == EAGAIN){
                break;
            }
            return false;
        }
        m_Request.m_read_idx += read_bytes;
    } while (is_ET_mode);  // loop for ET mode

//    string buf = m_Request.m_read_buffer;
//    LOG_DEBUG("req_data:\n%s", buf.c_str());

//    close(test_fd);
    return true;
}

bool HttpConnection::write_data(int *error) {
    if (m_bytes_to_send == 0) {
        return true;
    }

    long len = 0;
    while(true) {  // 循环发完为止
        len = writev(m_client_fd, m_iov, m_iov_cnt);

        if (len < 0) {
            *error = errno;
            if (errno == EAGAIN){
                // 内核写空间不足
                return true;
            }
            m_Response.unmap_file();
            return false;
        }

        m_bytes_have_sent += len;
        m_bytes_to_send -= len;

        // 发送完毕
        if (m_bytes_to_send <= 0) {
            m_Response.unmap_file();
            return true;
        }

        // 未发送完
        if (m_bytes_have_sent >= m_iov[0].iov_len) {
            // 响应头已发送完毕
            m_iov[0].iov_len = 0;
            m_iov[1].iov_base = m_Response.get_file_addr() + (m_bytes_have_sent - m_Response.m_write_idx);
            m_iov[1].iov_len = m_bytes_to_send;
        } else {
            // 响应头未发送完毕
            m_iov[0].iov_base = m_Response.m_write_buffer + m_bytes_have_sent;
            m_iov[0].iov_len -= m_bytes_have_sent;
        }

    }

}

bool HttpConnection::process() {
    HttpRequest::HTTP_CODE req_ret = m_Request.process_request();

    if (req_ret == HttpRequest::NO_REQUEST) {
        // 请求不完整
        return false;
    } else if (req_ret == HttpRequest::BAD_REQUEST){
        m_Response.init(m_src_dir, m_Request.get_path(), false, 400);
    } else {  // GET_REQUEST
        m_Response.init(m_src_dir, m_Request.get_path(), m_Request.is_keepalive(), 200);
    }

    m_Response.make_response(m_iov, &m_iov_cnt, &m_bytes_to_send);
    return true;
}

bool HttpConnection::is_keepalive() {
    return m_Request.is_keepalive();
}

int HttpConnection::get_fd() const {
    return m_client_fd;
}

struct sockaddr_in HttpConnection::get_sockaddr() const {
    return m_client_addr;
}

const char* HttpConnection::get_ip() const {
    return inet_ntoa(m_client_addr.sin_addr);
}

int HttpConnection::get_port() const {
    return m_client_addr.sin_port;
}




